package com.example.mediaplayerhw;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;

import com.example.mediaplayerhw.entity.VideoEntity;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    /**
     * 变量定义
     */
    private VideoView mVideoView;           //VideoView
    private MediaPlayer mMediaPlayer = new MediaPlayer();       //MediaPlayer对象
    private List<VideoEntity> mVideos = new ArrayList<>();      //用于存放视视频列表
    private int mCurrentIndex = -1;         //cursor所指向的数据库中行
    private TextView mVideoName;            //视频名称
    private TextView mCurrentTime;     //视频当前时间
    private TextView mVideoTotalTime;       //视频总时间
    private SeekBar mVideoProcess;          //视频进度
    private Button mControlVideo;           //控制视频播放和暂停
    private Button mNextVideo;              //下一个视频
    private boolean isHandsUp;          //手是否松开
    private boolean isFinished;             //判断视频是否结束
    // 定义想要获取的视频资源的数据库字段，包括id字段，display_name字段，data字段，Data字段存储的是视频的存储路径path
    private String[] mProjection = new String[]{
            MediaStore.Video.Media._ID,
            MediaStore.Video.Media.DISPLAY_NAME,
            MediaStore.Video.Media.DATA
    };


    @RequiresApi(api = Build.VERSION_CODES.O) //低版本支持
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();       //初始化布局控件
        getAuthorityAndInit(); //动态获取权限并且初始化视频列表
        isHandsUp = true;
        if (mVideos.size() >= 0) {
            //视频列表初始化完成后，设置第一个视频
            mVideoView.setVideoPath(mVideos.get(0).getmPath());

        }


        //使用mediaplay，关键是理解
        /**
         * The key to understand MediaPlayer is to understand the use of setOnPreparedListener and setOnCompletionListener.
         * setOnPreparedListener is invoked when a video or audio is prepared. when you call start() method, the video or
         * audio won't start to play unless they are prepared. When the video or audio is prepared, they will invoke onPrepared() method.
         * When the video or audio is completed, they will invoke onCompletion() method. u should set the datasource of a video or audio
         * at first, then you can initial some attributes in the onPrepared() method, when the video is complete, you can do some
         * work in the onCompletion() method.
         */
        mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                isFinished = false;
                mVideoName.setText(mVideos.get(mCurrentIndex).getmName());  //set video's name.
                mCurrentTime.setText("00:00");                              //set current time.
                mVideoProcess.setMax(mVideoView.getDuration());             //set max process of seekbar.
                mVideoTotalTime.setText(getFormatTime(mVideoView.getDuration())); //show the total time of video which gonna play.
                ProcessTask task = new ProcessTask(mVideoView, mVideoProcess, mCurrentTime); //start worker thread
                task.execute(isFinished);
            }
        });


        //一个视频播放完成后应该执行的操作
        mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if (mCurrentIndex < mVideos.size() - 1) {
                    mCurrentIndex++;
                    isFinished = true;
                    mVideoView.setVideoPath(mVideos.get(mCurrentIndex).getmPath());
                    mVideoView.start();   //执行start的时候，会执行setOnPreparedListener，系统会等待视频准备好之后，即onPrepared准备好之后，在播放视频。
                    mControlVideo.setText("暂停");
                }
            }
        });

        //invoke when seekbar process changed
        mVideoProcess.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                //if user drag the seekbar, the value of fromUser will set true value.
                if (fromUser) {
                    mVideoView.pause();
                    mCurrentTime.setText(getFormatTime(progress));
                    mVideoView.seekTo(progress);
//                    mVideoView.start();
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                isHandsUp = false;
                mVideoView.pause();
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                mVideoView.seekTo(seekBar.getProgress());
//                Log.i("=======拖动进度条====", Integer.toString(seekBar.getProgress())); // 打印松手后seekbar的位置
                Log.i("=======视频进度====", Integer.toString(mVideoView.getCurrentPosition())); // 打印松手后seekbar的位置
                mVideoView.start();
                isHandsUp = true;
            }
        });


        //播放和暂停处理
        mControlVideo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //如果视频列表中没有视频，则返回
                if (mCurrentIndex == -1) {
                    return;
                }
                //正在播放视频时，将按键字符设置为播放，并暂停视频，否则播放视频，并将按键改为暂停
                if (mVideoView.isPlaying()) {
                    mVideoView.pause();
                    mControlVideo.setText("播放");
                } else {
                    mVideoView.start();
                    mControlVideo.setText("暂停");
                }

            }
        });

        mNextVideo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mCurrentIndex < mVideos.size() - 1) {
                    mCurrentIndex++;
                    //mVideoList是初始化数据库中的视频文件
                    mVideoView.setVideoPath(mVideos.get(mCurrentIndex).getmPath());
                    mVideoProcess.setMax(mVideoView.getDuration());
                    mVideoName.setText(mVideos.get(mCurrentIndex).getmName());
                    mVideoTotalTime.setText(getFormatTime(mVideoView.getDuration()));
                    mCurrentTime.setText("00:00");
                    mControlVideo.setText("暂停");
                    mVideoView.start();
                } else {
                    Toast.makeText(MainActivity.this, "已经是最后一个视频", Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    //when the app is over, release the MediaPlayer object.
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mVideoView != null) {
            mVideoView.suspend();
        }
    }

    private String getFormatTime(int time) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("mm:ss");
        return dateFormat.format(new Date(time));
    }

    // 布局控件初始化函数
    private void initView() {
        mVideoView = findViewById(R.id.video_view);
        mVideoName = findViewById(R.id.video_name);
        mCurrentTime = findViewById(R.id.video_process_time);
        mVideoTotalTime = findViewById(R.id.video_total_time);
        mVideoProcess = findViewById(R.id.video_process);
        mControlVideo = findViewById(R.id.control_video);
        mNextVideo = findViewById(R.id.next_video);
    }

    // 初始化视频列表
    @RequiresApi(api = Build.VERSION_CODES.O)  //低版本支持
    private void initVideoList() {
        Cursor cursor = getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, mProjection, null, null, null);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                String id = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media._ID)); //获取视频资源id值
                String name = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME));//获取视频资源名称
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));//获取视频资源path
                mVideos.add(new VideoEntity(id, name, path));
            }
            if (mVideos.size() > 0) {
                mCurrentIndex = 0;
            }
        }
    }

    //动态申请权限
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void getAuthorityAndInit() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE
                    , Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
        else
            initVideoList();
    }

    //检查权限是否获取成功
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED)
            initVideoList();
        else
            Toast.makeText(this, "权限获取失败", Toast.LENGTH_SHORT).show();
    }

    //异步处理进度条
    private class ProcessTask extends AsyncTask<Boolean, Void, Void> {
        private VideoView videoView;  //获取当前播放进度
        private SeekBar seekBar;      //设置进度条显示当前播放进度
        private TextView textView;    //设置时间戳
        private int process;

        public ProcessTask(VideoView videoView, SeekBar seekBar, TextView textView) {
            this.videoView = videoView;
            this.seekBar = seekBar;
            this.textView = textView;
        }

        @Override
        protected Void doInBackground(Boolean... booleans) {
            while (true) {
                if(isHandsUp){
                    if (isFinished) {
                        Log.i("===============", "Video is Over");
                        break;
                    } else {
                        try {
                            /**
                             * 执行时跳转到onProgressUpdate回调方法，以便于刷新UI线程.
                             * publishProgress() method is used to trigger the onProgressUpdate() method even it's in the while(true) loop.
                             */
//                            Log.i("=======视频进度（异步）====", Integer.toString(seekBar.getProgress())); // 打印松手后seekbar的位置

                            publishProgress();
                            //The limit of human eye frames is 16ms, so set sleep time to 16ms, you will feel the seekbar is so smooth.
                            Thread.sleep(16);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }else {
                    try {
                        Thread.sleep(16);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
            return null;
        }

        //执行任务前：任务执行前调用
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        //执行任务后：任务执行完成后，doInBackground通过return返回给这个参数
        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            Log.i("================", "线程结束");
        }

        //状态更新:此函数的参数是doInBackground通过publishProgress传递过来的。
        @Override
        protected void onProgressUpdate(Void... voids) {
            super.onProgressUpdate();
            process = videoView.getCurrentPosition();
//            Log.i("======更新UI线程=======", Integer.toString(process));
            Log.i("=======视频进度（更新）====", Integer.toString(process)); // 打印松手后seekbar的位置

            if(isHandsUp){
                seekBar.setProgress(process);
                textView.setText(getFormatTime(process));
            }

        }

        //执行任务时,此方法的参数是第一个参数，从主线程的execute传递。
//        @Override
//        protected Void doInBackground(Void... videoViews) {
//            while (true) {
//                try {
//                    /**
//                     * 执行时跳转到onProgressUpdate回调方法，以便于刷新UI线程.
//                     * publishProgress() method is used to trigger the onProgressUpdate() method even it's in the while(true) loop.
//                     */
//                    publishProgress();
//                    //The limit of human eye frames is 16ms, so set sleep time to 16ms, you will feel the seekbar is so smooth.
//                    Thread.sleep(16);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
    }

}